package at.fhooe.engine.pandora;
//TODO rename packages

import at.fhooe.engine.entity.EntityManager;
import at.fhooe.engine.event.EventManager;
import at.fhooe.engine.event.SaveListenerStrategy;
import at.fhooe.engine.event.QueuedDispatchStrategy;
import at.fhooe.engine.event.events.WindowCloseRequestEvent;
import at.fhooe.engine.graphics.GraphicsSystem;
import at.fhooe.engine.input.InputManager;
import at.fhooe.engine.pathfinding.PathfindingManager;
import at.fhooe.engine.physics.PhysicsManager;
import at.fhooe.engine.scenegraph.SceneNodeManager;
import at.fhooe.engine.state.StateManager;
import at.fhooe.engine.time.FPSCounter;
import at.fhooe.engine.time.NanoClock;
import at.fhooe.engine.time.PandoraTimer;

public class Game {

	private static Game m_game = null;
	
	private EventManager m_eventManager;
	private InputManager m_inputManager;
	private EntityManager m_entityManager;
	private SceneNodeManager m_sceneNodeManager;
	private PhysicsManager m_physicsManager;
	private StateManager m_stateManager;
	private GraphicsSystem m_graphicsSystem;
	private NanoClock m_nanoClock;
	private FPSCounter m_fpsCounter;
	private PathfindingManager m_pathfindingManager;
	
	public static Game getInstance() {
		if (m_game == null) {
			m_game = new Game();
		}
		return m_game;
	}
	
	private Game() {
		m_graphicsSystem = new GraphicsSystem();
		m_inputManager = new InputManager();
		m_eventManager = new EventManager(new QueuedDispatchStrategy(), new SaveListenerStrategy());
		m_entityManager = new EntityManager();
		m_sceneNodeManager = new SceneNodeManager();
		m_physicsManager = new PhysicsManager();
		m_stateManager = new StateManager();
		m_nanoClock = new NanoClock();
		m_fpsCounter = new FPSCounter(false);
		m_pathfindingManager = new PathfindingManager();
	}
	
	public void startGame(int width, int height, int frames, boolean fullscreen) {
		m_graphicsSystem.open(width, height, fullscreen);
		m_graphicsSystem.setFPS(frames);
		m_graphicsSystem.addKeyListener(m_inputManager);
		m_graphicsSystem.addMouseListener(m_inputManager);
		m_graphicsSystem.addMouseMotionListener(m_inputManager);
		m_eventManager.addListener(m_graphicsSystem, WindowCloseRequestEvent.TYPE);
		m_pathfindingManager.allLoaded();
	}
	
	//TODO maybe name differently
	public PandoraTimer getPandoraTimerByName(String name) {
		if(m_nanoClock.getTimerByName(name) == null) {
			return m_nanoClock.createTimer(name);
		} else {
			return m_nanoClock.getTimerByName(name);
		}
	}
	
	public void update() {
		m_nanoClock.tick();

		m_fpsCounter.update();
		m_entityManager.update();
		m_physicsManager.update();
		m_eventManager.update();
		m_graphicsSystem.update();
		m_pathfindingManager.update();
	}

	public EventManager getEventManager() {
		return m_eventManager;
	}
	
	public InputManager getInputManager() {
		return m_inputManager;
	}
	
	public EntityManager getEntityManager() {
		return m_entityManager;
	}
	
	public PhysicsManager getPhysicsManager() {
		return m_physicsManager;
	}
	
	public SceneNodeManager getSceneNodeManager() {
		return m_sceneNodeManager;
	}
	
	public StateManager getStateManager() {
		return m_stateManager;
	}
	
	public GraphicsSystem getGraphicsSystem() {
		return m_graphicsSystem;
	}

	public double getDeltaTime() {
		return m_nanoClock.getDeltaTime();
	}
	
	public double getTimeSinceLastTick() {
		return m_nanoClock.timeSinceLastTick();
	}
	
	public void setFPS(int fps) {
		m_graphicsSystem.setFPS(fps);
	}
	
	public void displayFPSOn() {
		m_fpsCounter.turnOn();
	}
	
	public void displayFPSOff() {
		m_fpsCounter.turnOff();
	}
	
	public int getFPS() {
		return m_fpsCounter.getBufferdCounter();
	}
	
	public PathfindingManager getPathfindingManager() {
		return m_pathfindingManager;
	}
}
